package com.xixibaby.fadada.impl;


import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.xixibaby.core.Assert;
import com.xixibaby.fadada.ContractOnlineConfig;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;


import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;

@Setter
@Getter
@Slf4j
public class FadadaApiClient {

    @Autowired
    private ContractOnlineConfig fadadaConfig;


    /**
     * 法大大接口封装 无后置参数 无合同参数
     * @param url 接口地址
     * @param supplier 加密参数
     * @param clazz 返回参数封装
     * @param <T> 返回值泛型
     * @return 返回数据
     */
    public <T> T invork(String url, Consumer<Map<String, Object>> supplier, Class<T> clazz){
        return this.invork(url,supplier,clazz,(x)->{},null);
    }

    protected  <T> T invork(String url, Consumer<Map<String, Object>> supplier, Class<T> clazz, Consumer<Map<String, Object>> after, String contract){
        return this.invork(url,supplier,clazz,after,contract,"");
    }


    protected void log(String url,String timeStr,Map<String, Object> param,String result){
        log.info("法大大接口日志：[{}].[{}].[{}]",fadadaConfig.getUrl(),url, timeStr);
        log.info("法大大接口参数：[{}]",JSONObject.toJSONString(param));
        log.info("法大大接口返回：[{}]",result);
    }

    /**
     * 法大大接口封装
     * @param url 接口地址
     * @param supplier 参与加密的参数
     * @param clazz 返回参数封装
     * @param after 不参与加密但是必须的参数
     * @param contract 合同参数  每个合同都有自己的固定参数
     * @param <T> 返回值
     * @return
     */
    protected  <T> T invork(String url, Consumer<Map<String, Object>> supplier, Class<T> clazz, Consumer<Map<String, Object>> after, String contract,String md5){
        String timeStamp = this.getTimeStamp();
        Map<String, Object> param = new HashMap<>();
        supplier.accept(param);
        String msgDigest = getMsgDigest(timeStamp, param,contract,md5);
        param.put("app_id", fadadaConfig.getAppId());
        param.put("timestamp", timeStamp);
        param.put("v", fadadaConfig.getVersion());
        param.put("msg_digest", msgDigest);
        after.accept(param);
        String post = HttpUtil.post( fadadaConfig.getUrl() + url, param);
        this.log(url,timeStamp,param,post);
        JSONObject object = JSONObject.parseObject(post);
        String  data = object.containsKey("data") ?  object.get("data").toString() : "";
        String  msg = object.containsKey("data") && Assert.notEmpty(object.get("data"))  ?  object.get("data").toString() : object.get("msg").toString();
        Integer code = Integer.parseInt( object.get("code").toString());
        Assert.succ(code == 1 || code.equals(1000)).thenThrow("法大大接口错误！[{}]",msg);

        //兼容第二个人写的代码。。。。头疼死了
        if(code == 1000){
            data = post;
        }

        if(data.startsWith("{")){
            return JSONObject.parseObject(data,clazz);
        }else{
            if(clazz == Void.class){
                return null;
            }
            Assert.succ(clazz == String.class).thenThrow("不匹配的类型！");
            return (T) data;
        }
    }


    /**
     * 把参数转成 http url
     * @param url url头部
     * @param consumer 参与加密的部分
     * @param md5 需要参与md5的部分
     * @param after 不需要参与加密的参数
     * @return 拼装完后的参数
     */
    protected String buildUrl(String url, Consumer<Map<String, Object>> consumer, Consumer<Map<String, Object>> after, String md5){
        String timeStamp = this.getTimeStamp();
        StringBuilder sb = new StringBuilder(fadadaConfig.getUrl() + url);
        Map<String, Object> param = new HashMap<>();
        consumer.accept(param);
        String msgDigest = getMsgDigest(timeStamp, param,null, md5);
        param.put("app_id",fadadaConfig.getAppId());
        param.put("v",fadadaConfig.getVersion());
        param.put("timestamp",timeStamp);
        param.put("msg_digest",msgDigest);
        after.accept(param);
        String s = HttpUtil.toParams(param);
        sb.append("?").append(s);
        this.log("{no http}" + url ,timeStamp,param,sb.toString());
        return sb.toString();
    }


    private String getMsgDigest(String timeStr,Map<String, Object> parameters,String others){
        return this.getMsgDigest(timeStr,parameters,others,"");
    }


    /**
     * 法大大的签名校检
     * @param timeStr
     * @param parameters
     * @param others 合同参数
     * @return
     */
    private String getMsgDigest(String timeStr,Map<String, Object> parameters,String others,String md5){

        String[] codes = new String[parameters.size()];
        SortedMap<String, Object> paramMap = new TreeMap<>(parameters);
        int index = 0;

        for(Iterator var4 = paramMap.keySet().iterator(); var4.hasNext(); ++index) {
            String key = (String)var4.next();
            codes[index] = paramMap.get(key).toString();
        }

        try {
            StringBuilder parameter = new StringBuilder();
            String[] var5 = codes;
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                String str = var5[var7];
                if (Assert.notEmpty(str)) {
                    parameter.append(str);
                }
            }
            String other = Assert.notEmpty(others) ? others : "";
            String sha1 = sha1(fadadaConfig.getAppId() + md5(md5 + timeStr) + sha1(fadadaConfig.getSecret() + parameter.toString()) + other );
            return Base64.encode(sha1);
        } catch (Exception var9) {
            return "";
        }
    }

    private String getTimeStamp() {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(ts);
    }

    private String md5(String str){
        return SecureUtil.md5(str).toUpperCase();
    }

    private String sha1(String str){
        return SecureUtil.sha1(str).toUpperCase();
    }

//    private String base64(String str){
//        return Base64.encode(str);
//    }


    protected String getSignNodifyUrl() {
        return fadadaConfig.getSignNoticeUrl();
    }
    protected String getSignReturnUrl() {
        return fadadaConfig.getSignReturnUrl();
    }

    protected String getVerifyNodifyUrl() {
        return fadadaConfig.getVerifyNoticeUrl();
    }

    protected String getVefiryReturnUrl() {
        return fadadaConfig.getVerifyReturnUrl();
    }

    protected Integer getVerifyWay() {
        return fadadaConfig.getVerifyType();
    }

    protected String getAutoKeyWord() {
        return fadadaConfig.getCompanyAutoSignKeyWord();
    }

    protected Integer getCompanyVerifyWay() {
        return fadadaConfig.getCompanyVerifyType();
    }

}
